/*
 *
 * Monster Hunter Portable 2nd G PRX Project
 * Copyright (c) 2008 Mortimus
 * 
 */

#include <pspkernel.h>
#include <pspdebug.h>
#include <pspdisplay.h>
#include <pspsdk.h>
#include <pspctrl.h>
#include <stdio.h>
#include <string.h>
#include <pspsyscon.h>
#include <systemctrl.h>
#include "blit.h"
#include "apihook.h"

u32 hooked;
// kernel app
PSP_MODULE_INFO("Mortimus", 0x1000, 1, 1);
// Kernel Thread
PSP_MAIN_THREAD_ATTR(0);
//#define printf	pspDebugScreenPrintf

STMOD_HANDLER previous = NULL;
int complete = 0;
char displayme[255];
int OnModuleStart(SceModule2 *mod);

void somepointofmycode(){
		previous = sctrlHENSetStartModuleHandler(OnModuleStart);
}

int patchedsceUtilityLoadNetModule()
{
	ShowOutput("Function Called");
	//callApiHook(hooked);
	return callApiHook(hooked);
}

void Thread_List()
{
   SceUID thid[100];
   int thcount;
   sceKernelGetThreadmanIdList(SCE_KERNEL_TMID_Thread, thid, 100, &thcount);
   char s[64];
   sprintf(s, "(%d)", thcount);
   SceKernelThreadInfo thinfo;
   int i;
   char output[255];
   for(i = 0; i < thcount; i++)
   {
      memset(&thinfo, 0, sizeof(SceKernelThreadInfo));
      thinfo.size = sizeof(SceKernelThreadInfo);
      sceKernelReferThreadStatus(thid[i], &thinfo);
      sprintf(output,"Thread : %s ",thinfo.name);
      ShowOutput(output);
      sceKernelDelayThread(2500000);
      //printf("Thread : %s ",thinfo.name);
      //printf("\n");
   }
}

void module_List()
{
   SceUID modid[100];
   memset(modid, 0, 100 * sizeof(SceUID)); 
   int modcount;
   sceKernelGetModuleIdList(modid, 100 * sizeof(SceUID), &modcount);
   char s[64];
   sprintf(s, "(%d)", modcount);
   SceKernelModuleInfo minfo;
   int i;
   char output[255];
   for(i = 0; i < modcount; i++)
   {
      memset(&minfo, 0, sizeof(SceKernelModuleInfo));
      minfo.size = sizeof(SceKernelModuleInfo);
      sceKernelQueryModuleInfo(modid[i], &minfo);
      sprintf(output,"Module : %s", minfo.name);
      ShowOutput(output);
      //sceKernelDelayThread(2500000);
      if(minfo.name == "sceNetAdhoc_Library"){
	hooked = apiHookByNid2(modid[i], "sceNetAdhoc_Library", "sceNetAdhoc", 0xE08BDAC1, patchedsceUtilityLoadNetModule);
      };
      //printf("Module : %s ", minfo.name);
      //printf("\n");
   }
}

//int (*osceUtilityLoadNetModule)(void);

u32 PatchAdhoc(void)
{	
	//OutputText();
	ShowOutput("Patching");
	//void* oProcAddr;
	
	/*
	oProcAddr = (void*)pspFindProc("sceNetAdhoc_Library", "sceNetAdhoc", 0xE1D621D7);
  	strcpy (output,pspPatchProcCall(pspGetSysCallAddr((u32)oProcAddr), &patchedsceUtilityLoadNetModule));
  	osceUtilityLoadNetModule = (void*)oProcAddr;
	*/
	/*
	oProcAddr = (void*)pspFindProc("sceUtility_Driver", "sceUtility", 0x50C4CD57);
	pspPatchProcCall(pspGetSysCallAddr((u32)oProcAddr), &patchedUtilitySavedataInitStart);
	oUtilitySavedataInitStart = (void*)oProcAddr;
	*/
	//apiHookByNid("sceNetAdhoc_Library", "sceNetAdhoc", 0xE1D621D7, patchedsceUtilityLoadNetModule);
	//strcpy (output,"Patching done");
  
	return apiHookByNid("sceNetAdhoc_Library", "sceNetAdhoc", 0x7F75C338, patchedsceUtilityLoadNetModule);
}

int OnModuleStart(SceModule2 *mod){
		ShowOutput(mod->modname);
		//sceKernelDelayThread(2500000);
		if (strcmp(mod->modname, "sceVshNetconf_Module") == 0)
		{
			//strcpy (output,"Patching Module");
			// Do something with vsh module here
			hooked = PatchAdhoc();
			//complete = 1;
			//module_List();
			//Thread_List();
		}
		//strcpy(output, (*sctrlHENFindDriver("sceNetAdhoc_Library"))->name);
		//*mod = sceKernelFindModuleByName("sceNetAdhoc_Library");
		//strcpy(output, mod->modname);
		if (!previous)
			return 0;

		// Call previous handler

		return previous(mod);
}

int main_thread(SceSize args, void *argp)
{
	//pspDebugScreenInit();
	ShowOutput("Thread Started");
	//printf("Thread Started");

	sceKernelDelayThread(7000000);

	//while(complete == 0){
	//pspSdkSetK1(1);
	//hooked = PatchAdhoc();
	//pspSdkSetK1(0);

	somepointofmycode();

	//module_List();
	//u32 mod_id = sceKernelLoadModule("flash0:/kd/pspnet_adhoc.prx", 0, NULL);
	//sceKernelStartModule(mod_id, 0, NULL, NULL, NULL); 
	//sceKernelDelayThreadCB(5000);
	//};
	//hooked = PatchAdhoc();
	//strcpy (output,"Patching done");
	//strcpy (output,"Thread Ended");
  
	sceKernelSleepThreadCB();

	return 0;
}

int disp_thread(SceSize args, void *argp){
	while(1){
	blit_string(1, 1, displayme, 0xffffff, 0x000000);
	sceKernelDelayThreadCB(5000);
	}
	return 0;
}

/* Entry point */
int module_start(SceSize args, void *argp)
{ 
	ShowOutput("Module Started");
	int thid;
	initApiHooks();

	thid = sceKernelCreateThread("Mortimus", main_thread, 0x18, 0x10000, PSP_MEMORY_PARTITION_KERNEL, NULL);
	if(thid >= 0)
	{
		sceKernelStartThread(thid, args, argp);
	}
	thid = sceKernelCreateThread("Output", disp_thread, 0x18, 0x10000, 0, NULL);
	if(thid >= 0)
	{
		sceKernelStartThread(thid, args, argp);
	}
	return 0;
}

/* Module stop entry */
int module_stop(SceSize args, void *argp)
{
	return 0;
}
/*
Modules loaded when entering guild hall
scePafHeaparea_Module
scePaf_Module
sceVshCommonUtil_Module
sceDialogmain_Module
sceVshNetconf_Module

Modules loaded when game started
sceMeCodecWrapper
sceImpose_Driver
sceKernelLibrary
sceNetAdhocAuth_Service
sceAvcodec_wrapper
sceSAScore
sceATRAC3plus_Library
sceChnnlsv
sceVshSDAuto_Module

Modules loaded with boot of game
sceSystemMemoryManager
sceLoaderCore
sceExceptionManager
sceInterruptManager
sceThreadManager
sceDMAManager
sceSystimer
sceIOFileManager
sceMemlmd
sceModuleManager
SystemControl
sceInit
sceLoadExec
sceLowIO_Driver
sceGE_Manager
sceIdStorage_Service
sceSYSCON_Driver
sceRTC_Service
sceLFatFs_Driver
sceClockgen_Driver
sceWM8750_Driver
sceAudio_Driver
sceDisplay_Service
sceController_Service
sceLED_Service

Threads
audiomixer
audioinput
hpremote
powermain
powerbattery
umdmanmount
umdmantask

mscmmain
mscmmedia
fatmsmedia
wlanMac
msstrosleep
flush
mortimus
output
scewlanHal
sceImpose
user_main
prioritychanger
checkexitgame
fakerofsloader
sha1thread
transferthread
Csepspsnd
csepsp
csepspatrac
scenetcallout
scenetintr
scenetadhocctl
scedialog
scepafthread
scewaveutility
scepafjob
scemomgrstart
*/
